package com.gitee.cnlongs.cnlongmq.server.threads;

import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.gitee.cnlongdb.basic.entity.datasync.CnLongDataSyncRequest;
import com.gitee.cnlongdb.basic.entity.datasync.CnLongDataSyncResponse;
import com.gitee.cnlongdb.basic.enums.sysnc.LongdbDataSyncEnms;
import com.gitee.cnlongdb.basic.utils.RandomUtil;
import com.gitee.cnlongdb.server.datasync.DataSyncConnectMessage;
import com.gitee.cnlongs.cnlongmq.basic.constant.CnLongMqConstant;
import com.gitee.cnlongs.cnlongmq.basic.entitiy.election.CaptainElectionEntity;
import com.gitee.cnlongs.cnlongmq.basic.entitiy.request.CnLongMqConfiger;
import com.gitee.cnlongs.cnlongmq.basic.entitiy.request.CnLongRequest;
import com.gitee.cnlongs.cnlongmq.basic.enums.CnLongMqDataSync;
import com.gitee.cnlongs.cnlongmq.server.LongMqServer;

/**
 * 系统名称：ElectionCaptainSequeueHandler
 * 模块名称：
 * 模块描述：队长选举操作工具类
 * 功能列表：
 * 模块作者：zouyong
 * 开发时间：2019年8月1日 下午4:37:48
 * 模块路径：com.gitee.cnlongs.cnlongmq.server.threads.ElectionCaptainSequeueHandler
 */
public class ElectionCaptainSequeueHandler {

	private static final Logger logger = (Logger) LoggerFactory.getLogger(ElectionCaptainSequeueHandler.class);
	
	/**
	 * 功能描述：开始【队长选举】操作
	 × 模块作者：ZOUYONG
	 × 开发时间：2019年8月2日 下午12:19:25
	 × 返回数据：void
	 */
	public static void startElectionCaptainOperator(CnLongMqConfiger longMqConfig) {
		if(null == longMqConfig) {
			longMqConfig = LongMqServer.getExecuter().getLongMqConfig();
		}
		// 获取当前应用的【队长】信息
		String captainElectionSequeue = longMqConfig.getCaptainElectionSequeue();
		// 如果没有选举队长，则进行选举
		if(StringUtils.isBlank(captainElectionSequeue)) {
			// 优先选举自己为队长
			captainElectionSequeue = longMqConfig.electionOwnCaptain();
			// 执行队长选举操作
			execCaptainElectionOperator(captainElectionSequeue, longMqConfig);
		}
	}

	/**
	 * 功能描述：执行队长选举操作
	 × 模块作者：ZOUYONG
	 × 开发时间：2019年8月1日 下午7:53:18
	 × 返回数据：void
	 */
	private static void execCaptainElectionOperator(String captainElectionSequeue, CnLongMqConfiger longMqConfig) {
		// 将要选举队长的信息，记录下来作为后补队长
		updateWaitCaptainElection(captainElectionSequeue, longMqConfig);	
		// 并通知其他应用：获取当前应用列表
		List<String> applicaitonList = longMqConfig.getApplicationList();
		if(CollectionUtils.isEmpty(applicaitonList)) {
			logger.info("没有执行[选举队长]操作，因为关联应用为空！");
			return;
		}
		
		String alreadyCaptainElectionSeq = null;	// 竞选成功的队长信息
		for (int i=0; i<applicaitonList.size(); i++) {
			String seqStr = applicaitonList.get(i);
			try {
				if(captainElectionSequeue.indexOf(seqStr) < 0) {
					String[] seqAry = seqStr.split(CnLongMqConstant.longmqSeparateF);
					// 定义基础请求对象
					CnLongRequest request = new CnLongRequest();
					request.setIp(longMqConfig.getLongMqIp());
					request.setPort(longMqConfig.getLongMqPort());
					request.getParams().put("captainElectionSequeue", captainElectionSequeue);
					// 定义消息通信请求对象
					CnLongDataSyncRequest dataSync = new CnLongDataSyncRequest();
					dataSync.setMessageType(CnLongMqDataSync.electionCaptain.name());
					dataSync.setClassPath(ElectionCaptainSequeueHandler.class.getName());
					dataSync.setMethodName("receiveElectionCaptainSequeue");
					dataSync.setParamClas(new String[]{ request.getClass().getName() });
					dataSync.setParamObject(new String[]{ JSON.toJSONString(request) });
					dataSync.setOperThreadId(RandomUtil.getCharAndNumr(20));
					// 开始发送netty消息，通知相关应用进行队长选举
					CnLongDataSyncResponse response = DataSyncConnectMessage.noticeDataSyncSend(seqAry[0], Integer.valueOf(seqAry[1]), dataSync);
					if(LongdbDataSyncEnms.success.name().equals(response.getReturnCode())) {
						String captainElectionResult = response.getJsonData();
						// 如果竞选队长失败，则直接将返回的结果作为后补队长
						if(StringUtils.isNotBlank(captainElectionResult) && 
								!LongdbDataSyncEnms.electionCaptainSuccess.name().equals(captainElectionResult)) {
							String[] results = captainElectionResult.split(CnLongMqConstant.longmqSeparateE);
							for (String election : results) {
								// 将要选举队长的信息，记录下来作为后补队长
								updateWaitCaptainElection(election, longMqConfig);
							}
							if(results[0].equals(alreadyCaptainElectionSeq)) {
								continue;
							}
							if(StringUtils.isBlank(alreadyCaptainElectionSeq)) {
								alreadyCaptainElectionSeq = results[0];
							} else {
								String[] oldAry = alreadyCaptainElectionSeq.split(CnLongMqConstant.longmqSeparateF);
								String[] newAry = results[0].split(CnLongMqConstant.longmqSeparateF);
								if(Long.valueOf(newAry[2]) < Long.valueOf(oldAry[2])) {
									alreadyCaptainElectionSeq = results[0];
								}
							}
							longMqConfig.setCaptainElectionSequeue(alreadyCaptainElectionSeq);
						}
					}
				}
			} catch(Exception e) {
				logger.error("通知应用[{}]选举成队长的消息异常：{}", e.getMessage());
			}
		}
		// 如果本次竞选的队长信息 与 需要竞选的队长信息不相同，则再次发起竞选
		if(StringUtils.isNotBlank(alreadyCaptainElectionSeq) && 
				!alreadyCaptainElectionSeq.equals(captainElectionSequeue)) {
			execCaptainElectionOperator(alreadyCaptainElectionSeq, longMqConfig);
		}
	}
	
	/**
	 * 功能描述：接收队长选举的操作
	 × 模块作者：ZOUYONG
	 × 开发时间：2019年8月1日 下午4:39:07
	 × 返回数据：String
	 */
	public static String receiveElectionCaptainSequeue(CnLongRequest request) {
		StringBuffer result = new StringBuffer();
		String waitCaptain = null;
		try {
			// 获取传入竞选的【队长】信息
			waitCaptain = request.getParams().get("captainElectionSequeue");
			// 获取当前应用的【队长】信息
			String captainElectionSequeue = LongMqServer.getExecuter().getLongMqConfig().getCaptainElectionSequeue();
			// 如果没有选举队长，则直接接受对方为队长
			if(StringUtils.isBlank(captainElectionSequeue)) {
				LongMqServer.getExecuter().getLongMqConfig().setCaptainElectionSequeue(waitCaptain);
			}
			else {
				String[] oldAry = waitCaptain.split(CnLongMqConstant.longmqSeparateF);
				String[] newAry = captainElectionSequeue.split(CnLongMqConstant.longmqSeparateF);
				// 比较选举时间，如果传入的【对长时间】早于【当前对长】的时间，则【传入的队长时间】获胜
				if(Long.valueOf(oldAry[2]) < Long.valueOf(newAry[2])) {
					LongMqServer.getExecuter().getLongMqConfig().setCaptainElectionSequeue(waitCaptain);
				} else {
					result.append(captainElectionSequeue);
				}
			}
		}
		catch(Exception e) {
			logger.error("接收队长选举的操作异常：{}", e.getMessage());
		}
		
		CnLongMqConfiger longMqConfig = LongMqServer.getExecuter().getLongMqConfig();
		// 将要选举队长的信息，记录下来作为后补队长
		updateWaitCaptainElection(waitCaptain, longMqConfig);
		
		// 将选举成功的队长信息 和 本应用的信息一同返回
		if(StringUtils.isNotBlank(result.toString())) {
			result.append(CnLongMqConstant.longmqSeparateE)
				.append(longMqConfig.getLongMqIp())
				.append(CnLongMqConstant.longmqSeparateF)
				.append(longMqConfig.getLongMqPort())
				.append(CnLongMqConstant.longmqSeparateF)
				.append(longMqConfig.getCaptainElectionTime())
			;
		}
		
		return StringUtils.isNotBlank(result.toString()) ? result.toString() : LongdbDataSyncEnms.electionCaptainSuccess.name();
	}

	/**
	 * 功能描述：将要选举队长的信息，记录下来作为后补队长
	 × 模块作者：ZOUYONG
	 × 开发时间：2019年8月30日 上午10:59:52
	 × 返回数据：void
	 */
	public static void updateWaitCaptainElection(String waitCaptain, CnLongMqConfiger longMqConfig) {
		try {
			String[] ary = waitCaptain.split(CnLongMqConstant.longmqSeparateF);
			String key = ary[0] + CnLongMqConstant.longmqSeparateF + ary[1];
			CaptainElectionEntity catainElection = new CaptainElectionEntity();
			catainElection.setCaptainIp(ary[0]);
			catainElection.setCaptainPort(Integer.valueOf(ary[1]));
			catainElection.setElectionTime(Long.valueOf(ary[2]));
			longMqConfig.getCaptainElectionMap().put(key, catainElection);
		}
		catch(Exception e) {
			logger.error("更新后补队长信息异常：{}", e.getMessage());
		}
	}
	
}
